package com.jmx.mstcodesandbox.javasandbox;

import cn.hutool.core.io.FileUtil;
import com.jmx.mstcodesandbox.CodeSandBox;
import com.jmx.mstcodesandbox.model.ExecuteCodeRequest;
import com.jmx.mstcodesandbox.model.ExecuteCodeResponse;
import com.jmx.mstcodesandbox.model.JudgeInfo;
import com.jmx.mstcodesandbox.model.ProcessInfo;
import com.jmx.mstcodesandbox.utils.ProcessUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public abstract class JavaAbstractCodeSandBoxTemplate implements CodeSandBox {
    public static final String GLOBAL_JAVA_CODE_DIR = "temp";
    public static final String USER_CODE_FILE_NAME = "Main.java";
    public static final String USER_CODE_CLASS_NAME = "Main";
    public static final long EXEC_TIME_OUT = 5000L;

    private static final String GLOBAL_CODE_PATH;

    static {
        String userDir = System.getProperty("user.dir");
        GLOBAL_CODE_PATH = userDir + File.separator + GLOBAL_JAVA_CODE_DIR;
        if (!FileUtil.exist(GLOBAL_CODE_PATH)) {
            FileUtil.mkdir(GLOBAL_CODE_PATH);
        }
    }

    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        List<String> inputs = executeCodeRequest.getInputs();
        String code = executeCodeRequest.getCode();

        // 使用单独的文件夹隔离用户代码
        String userCodeDir = GLOBAL_CODE_PATH + File.separator + UUID.randomUUID();
        String userCodeFilePath = userCodeDir + File.separator + USER_CODE_FILE_NAME;
        // 将代码写入文件
        File userCodeFile = FileUtil.writeUtf8String(code, userCodeFilePath);
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        executeCodeResponse.setMessage("程序运行完成");
        executeCodeResponse.setStatus(0);
        // 编译代码
        String compileCmd = String.format("javac -encoding utf-8 %s", userCodeFile.getAbsolutePath());
        ProcessInfo compileProcessInfo = ProcessUtil.executeCmd(compileCmd);
        if (compileProcessInfo.getCode() != 0) {
            executeCodeResponse.setMessage("代码编译失败:" + compileProcessInfo.getMessage());
            executeCodeResponse.setStatus(compileProcessInfo.getCode());
            // 编译失败后直接返回
            return executeCodeResponse;
        }

        List<String> outputs = new ArrayList<>();
        long maxTime = 0L;
        long maxMemory = 0L;
        // 执行用户程序
        for (String input : inputs) {
            ProcessInfo processInfo = execute(input,userCodeDir);
            Long time = processInfo.getTime();
            Long memory = processInfo.getMemory();
            if (time != null) {
                maxTime = Math.max(maxTime, time);
            }
            if (memory != null) {
                maxMemory = Math.max(memory, maxMemory);
            }
            String message = processInfo.getMessage();
            if (processInfo.getCode() != 0) {
                executeCodeResponse.setStatus(processInfo.getCode());
                executeCodeResponse.setMessage(message);
            }
            outputs.add(message);
        }
        executeCodeResponse.setOutputs(outputs);
        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setTime(maxTime);
        judgeInfo.setMemory(maxMemory);
        executeCodeResponse.setJudgeInfo(judgeInfo);

        //清理文件
        boolean del = FileUtil.del(userCodeDir);
        System.out.println("删除"+(del?"成功":"失败"));
        return executeCodeResponse;
    }

    /**
     * 底层执行Java代码的方法
     * @param inputArgs 参数
     * @param userCodeDir 用户代码存放的路径
     * @return 程序执行的信息
     */
    public abstract ProcessInfo execute(String inputArgs,String userCodeDir);
}
